home *** CD-ROM | disk | FTP | other *** search
/ PC Media 22 / PC MEDIA CD22.iso / share / prog / datalib2 / dataexe2.cpp < prev    next >
C/C++ Source or Header  |  1995-08-14  |  14KB  |  409 lines

  1. /*
  2.  
  3.  This is part 2 of the expression evaluator
  4.  
  5. */
  6.  
  7. #include "datapriv.hpp"
  8.  
  9.  
  10. /************************************************************************
  11.  
  12.  This is the actual expression evaluator, it takes a pointer to a pointer
  13.  to a string, and returns an integer representing the value of the string.
  14.  
  15.  It also updates the string pointer to point to the first character after
  16.  the expression.
  17.  
  18. ************************************************************************/
  19.  
  20.  
  21. op *expval::exeval(char **s,record *recp)
  22. {
  23.  char ws[255],*wsp,*wsp1;
  24.  struct op *rv;
  25.  
  26.  exworkp=exwork;
  27.  
  28.  if (**s==EXSTART) rv=evalstr(s,0,recp);    /* Already tokenised */
  29.  else
  30.  {
  31.   wsp1=ws;
  32.   wsp=exetoken(*s,&wsp1);     /* Tokenise the string */
  33.   wsp1=ws;
  34.   rv=evalstr(&wsp1,0,recp);
  35.   *s=wsp;
  36.  }
  37.  
  38.  memcpy(&retop,rv,sizeof(struct op));
  39.  return(&retop);
  40. }
  41.  
  42.  
  43.  
  44. /*
  45.    This routine evaluates a tokenised string, returning an integer which
  46.    is the value of the string.
  47.  
  48.    It takes a pointer to a pointer to a string, and updates it to point to
  49.    the first character after the expression, it is recursive, lop should
  50.    point be the priority of a previous operator, and initially should be set
  51.    to 0.
  52.    
  53. */
  54.  
  55. op *expval::evalstr(char **s,int ilop,record *recp)
  56. {
  57.  int end=0;                // flag end of expression
  58.  int thisst=0;                // Shows this started with EXSTART
  59.  struct op funcpar[16];            // function parameters
  60.  struct op *fo,*so;            /* First and second operands */
  61.  char c;                /* Temporary char */
  62.  time_t tclock;                /* Current time */
  63.  struct tm *tms;
  64.  char *wsp;                /* Local work space */
  65.  int lop=ilop;
  66.  int x,y,z;                // useful ints
  67.  field *f;                // field
  68.  double rnum,fnum,snum;            // Floats used in evaluation
  69.  int rint,fint,sint;            // Integers used in evaluation
  70.  int rlen,flen;                // Length of result,1st op
  71.  char *rstr,*fstr;            // First string, Result string
  72.  int copflag;
  73.  
  74.  if (**s==EXSTART) {(*s)++; lop=0; thisst=1;}    /* Skip expression marker */
  75.  
  76.  c=**s; (*s)++;
  77.  
  78.  fo=(struct op *)exealloc(sizeof(struct op));
  79.  fo->optype=OPINT;
  80.  fo->num=0;
  81.  
  82.  if (c<0)    /* Must be a number or string of some sort */
  83.   switch(c)
  84.   {
  85.    case    EXINT    : fo->num=**(double **)s; *s+=sizeof(double);
  86.              break;
  87.   
  88.    case    EXVAR   : x=**(int **)s; *s+=sizeof(int);
  89.              f=db->getfield(x);
  90.                   switch(f->type)
  91.                   {
  92.            case 'C' : fo->optype=OPSTR;
  93.                   fo->str=exealloc(f->getlen()+1);
  94.                               strcpy(fo->str,recp->getfield(x,0));
  95.                               fo->oplen=f->getlen();
  96.                               break;
  97.                    case 'N' : fo->num=atof(recp->getfield(x)); break;
  98.                    case 'L' : fo->optype=OPLOG; 
  99.                              x=*(char *)(recp->getfield(x)) & 0xdf;
  100.                              fo->num=(x=='Y' || x=='T') ? 1 : 0; break;
  101.                    case 'D' : fo->optype=OPDATE;
  102.                              strncpy(fo->date,recp->getfield(x),8);
  103.                               fo->date[8]=0;
  104.                   break;
  105.                    case 'M' : fo->optype=OPSTR; fo->str=recp->getfield(x,0);
  106.                              if (recp->indflg) err("No Memo in index");
  107.                               break;
  108.                   }
  109.              break;
  110.              
  111.    case EXSTR    : fo->optype=OPSTR; fo->str=strcpy(exealloc(strlen(*s)+1),*s);
  112.              fo->oplen=strlen(fo->str);
  113.              while(**s) (*s)++; (*s)++;
  114.              break;
  115.             
  116.    case    EXSTART    : (*s)--; fo=evalstr(s,0,recp); break;
  117.             
  118.    default    : err("Error in expression - a"); goto errend;
  119.   }
  120.  else                 /* Must be an operator, or a function */
  121.   if (oppt[c].type==BINARY)
  122.      {err("Error in expression - b"); goto errend;}
  123.   else
  124.   {
  125.    so=funcpar+1;
  126.    if ((oppt[c].type!=FUNCTION) || ((oppt[c].type==FUNCTION) && oppt[c].pri))
  127.    {
  128.     // Now for a function collect the correct number of parameters, however
  129.     // to speed the program type checking is performed on the first 2
  130.     // parameters, and fo copies the 1st par. and so points to the 2nd
  131.     // The only parameter retained is fo.
  132.  
  133.     if (oppt[c].type>=FUNCTION)
  134.     {
  135.      for(int i=0; i<oppt[c].pri+oppt[c].type-4; funcpar[i++]=*evalstr(s,99,recp));
  136.      *fo=funcpar[0];
  137.      if (!(fo->optype & oppt[c].type1) ||
  138.       (oppt[c].pri>1 && !(so->optype & oppt[c].type2)))
  139.     {err("Wrong operand type F"); goto errend;}
  140.     }
  141.     else    // Unary operator, pick up the operand
  142.     {
  143.      fo=evalstr(s,oppt[c].num==NOT ? oppt[c].pri : 99,recp);
  144.      if (!(fo->optype & oppt[c].type1))
  145.     {err("Wrong operand type 1"); goto errend;}
  146.     }
  147.    }
  148.    if (fo->optype==OPINT || fo->optype==OPLOG) {fint=fnum=fo->num;}
  149.    if (fo->optype==OPSTR) {fstr=fo->str; flen=strlen(fstr)+1;}
  150.    if (so->optype==OPINT) {sint=snum=so->num;}
  151.    if (oppt[c].optype) fo->optype=oppt[c].optype;
  152.    rlen=fo->oplen;
  153.    rint=-1000;
  154.    copflag=1;        // Show if result needs copying after evaluation
  155.    switch(oppt[c].num)    // Unary operations
  156.    {
  157.     case PLUS    : copflag=0; break;
  158.     case MINUS    : rnum=-fnum; break;
  159.     case NOT    : rint=(!fint) ? -1 : 0; break;
  160.     case ABS    : rnum=fabs(fnum); break;
  161.     case ASC    : rint=*fstr; break;
  162.     case AT    : wsp=strstr(so->str,fstr); 
  163.              rint=(wsp) ? wsp-so->str+1 : 0; break;
  164.     case CDOW    : rstr=strcpy(exealloc(9),cdow(fo->date)); rlen=9; break;
  165.     case CHR    : rstr=exealloc(2); *rstr=fint; rstr[1]=0; rlen=1; break;
  166.     case CMONTH : rstr=strcpy(exealloc(10),cmonth(fo->date)); rlen=9; break;
  167.     case CTOD    : rstr=fstr; ctod(fo->date,rstr); break;
  168.     case DATE    : time(&tclock); strcpy(fo->date,getdate(tclock)); break;
  169.     case DAY    : gnums(fo->date,rint,y,z); break;
  170.     case DOW    : rint=dow(fo->date); break;
  171.     case DTOC    : rstr=exealloc(11); gnums(fo->date,x,y,z);
  172.               sprintf(rstr,"%02d/%02d/%02d",x,y,z%100); rlen=8;
  173.                   break;
  174.     case DTOS    : rstr=strcpy(exealloc(9),fo->date); rlen=8; break;
  175.     case IIF    : if (recp->indflg)
  176.                   {
  177.                    if (so->optype!=funcpar[2].optype) err("Inv Ind");
  178.                    rlen=(so->oplen>funcpar[2].oplen) ? 
  179.                                 so->oplen : funcpar[2].oplen;
  180.                   }
  181.                   if (fint) *fo=*so; else *fo=funcpar[2]; copflag=0; 
  182.                   break;
  183.     case INT    : rnum=(fnum>=0) ? floor(fnum) : ceil(fnum); break;
  184.     case ISALPHA: rint=isalpha(*(fstr)); break;
  185.     case ISDIGIT: rint=isdigit(*(fstr)); break;
  186.     case ISLOWER: rint=islower(*(fstr)); break;
  187.     case ISUPPER: rint=isupper(*(fstr)); break;
  188.     case LEFT   : if (sint<1) {*fstr=0; rlen=0;}
  189.               else {if (flen-1>sint) fstr[sint]=0; rlen=sint;}
  190.               copflag=0; break;
  191.     case LOWER  : rstr=strlwr(fstr); break;
  192.     case UPPER  : rstr=strupr(fstr); break;
  193.     case LTRIM  : rstr=fstr; while(*rstr==' ') rstr++; break;
  194.     case LEN    : rint=flen-1; break;
  195.     case MAX    : if (fo->optype==OPDATE)
  196.                    {if (strcmp(fo->date,so->date)<0) *fo=*so;}
  197.                   else if (fnum<snum) *fo=*so;
  198.                   copflag=0;
  199.                   break;
  200.     case MIN    : if (fo->optype==OPDATE)
  201.                    {if (strcmp(fo->date,so->date)>0) *fo=*so;}
  202.                   else if (fnum>snum) *fo=*so;
  203.                   copflag=0;
  204.                   break;
  205.     case MOD    : rnum=fmod(fnum,snum); break;
  206.     case MONTH    : gnums(fo->date,x,rint,z); break;
  207.     case RECCOUNT  : rnum=db->getnrec(); break;
  208.     case RECNO     : rnum=recp->getrecnum(); break;
  209.     case RECSIZE   : rint=db->getreclen(); break;
  210.     case REPLICATE :
  211.                   rstr=exealloc(flen*sint); *rstr=0; rlen=sint*(flen-1);
  212.                   for(x=0; x<sint; x++) strcat(rstr,fstr);
  213.                   break;
  214.     case RIGHT  : if (sint<1) {*fstr=0; rlen=0;}
  215.                 else {if (sint<flen-1) fstr+=flen-1-sint; rlen=sint;}
  216.                   rstr=fstr; break;
  217.     case ROUND  : if (snum>=0)
  218.           {
  219.                    wsp=exealloc(32); sprintf(wsp,"%%.%df",sint);
  220.                sprintf(exworkp,wsp,fnum); rnum=atof(exworkp);
  221.                    exworkp=wsp;
  222.                   }
  223.                   else    // Negative rounding
  224.                   {
  225.                    rnum=floor(fnum/pow(10,-sint)+0.5)*pow(10,-sint);
  226.                   }
  227.                   break;
  228.     case TRIM    :
  229.     case RTRIM    : rstr=rtrim(fstr); break;
  230.     case SOUNDEX: rstr=soundex(exealloc(5),fstr); rlen=4; break;
  231.     case SPACE    : if (fint<0) fint=0; 
  232.               rstr=wsp=exealloc(1+fint); rlen=fint;
  233.               while(wsp<exworkp-1) *wsp++=' '; *wsp=0;
  234.                   break;
  235.     case STR    : wsp=exealloc(32);
  236.               if (funcpar[2].optype!=1) {err("No. expected"); goto errend;}
  237.                x=(sint==-1) ? 10 : sint;
  238.                   y=(funcpar[2].num==-1) ? 0 : funcpar[2].num;
  239.               sprintf(wsp,"%%%d.%df",x,y);
  240.                     sprintf(exworkp,wsp,fnum); exworkp[x]=0;
  241.               rstr=exealloc(strlen(exworkp)+1); 
  242.                   rlen=x;
  243.               break;
  244.     case STUFF  : if (funcpar[2].optype!=OPINT || funcpar[3].optype!=OPSTR)
  245.                {err("Wrong par. type"); goto errend;}
  246.               x=sint; if (!x) x=1;
  247.               rstr=exealloc(strlen(funcpar[3].str)+flen);
  248.                   strcpy(rstr,fstr);
  249.                   if (x>strlen(rstr))
  250.                    {fo->str=strcat(rstr,funcpar[3].str); break;}
  251.                   rstr[x-1]=0; strcat(rstr,funcpar[3].str);
  252.           if(x+funcpar[2].num<flen)
  253.            strcat(rstr,fstr+(int)(x+(int)(funcpar[2].num)-1));
  254.                   rlen=fo->oplen-funcpar[2].num;
  255.                   if (rlen<0) rlen=0;
  256.                   rlen+=sint-1+funcpar[3].oplen;
  257.                   break;
  258.     case SUBSTR : if (sint<1) {*fstr=0; rlen=0;}
  259.               else if (sint<flen-1)
  260.                   {
  261.                    fstr+=sint-1;
  262.                    x=funcpar[2].num;
  263.                    if (x>0 && x<strlen(fstr)) *(fstr+x)=0;
  264.                    rlen=(x>0) ? x : fo->oplen-sint+1;
  265.                   }
  266.                   rstr=fstr; break;
  267.     case SWAPDATA: rstr=swapdata(fstr); break;
  268.     case TIME    : time(&tclock); rstr=exealloc(30);
  269.               strcpy(rstr,asctime(localtime(&tclock))+11); rlen=8;
  270.                   rstr[8]=0;
  271.               break;
  272.     case TYPE   : rstr=exealloc(2); rstr[1]=0;
  273.                switch(fo->optype)
  274.                   {
  275.                    case OPINT  : *rstr='N'; break;
  276.                    case OPSTR  : *rstr='C'; break;
  277.                    case OPDATE : *rstr='D'; break;
  278.                    case OPLOG  : *rstr='L'; break;
  279.                   }
  280.                   fo->optype=OPSTR; rlen=1; break;
  281.     case VAL    : rnum=atof(fstr); break;
  282.     case YEAR    : gnums(fo->date,x,y,rint); break;
  283.    }
  284.    fo->oplen=rlen;    // Copy in results
  285.    if (copflag)
  286.    {
  287.     if (fo->optype==OPINT || fo->optype==OPLOG) 
  288.         fo->num=(rint!=-1000) ? rint : rnum;
  289.     if (fo->optype==OPSTR) fo->str=rstr;
  290.    }
  291.   }
  292.  
  293.  while(!end)
  294.  {
  295.   // We should now be pointing at the end of expression or a binary operator 
  296.   // fo has been set to the value of the first operand
  297.  
  298.   c=**s; (*s)++;
  299.   if (c==EXEND) {end=1; if (!thisst) (*s)--; return(fo);}  // ret - end expr. 
  300.  
  301.   if (c<=OBRAC) {err("Error in expression - c"); goto errend;}
  302.  
  303.   if (oppt[c].pri<=lop) {(*s)--; return(fo);}    /* return if priority lower */
  304.   
  305.   so=evalstr(s,oppt[c].pri,recp);
  306.   
  307.   if (!((fo->optype & oppt[c].type1) && (so->optype & oppt[c].type2)))
  308.      {err("Wrong operand type 2"); goto errend;}
  309.  
  310.   switch(oppt[c].num)        /* Binary Operators */
  311.   {
  312.    case PLUS    :
  313.    case MINUS    : plumin(fo,so,oppt[c].num); break;
  314.    case DOLLAR    : fo->num=(strstr(so->str,fo->str)!=0); fo->optype=OPLOG; break;
  315.    case POW2    :
  316.    case POW    : fo->num=pow(fo->num,so->num); break;
  317.    case TIMES    : fo->num*=so->num; break;
  318.    case DIVIDE    : if (!so->num) {err("Divide by 0"); goto errend;}
  319.                   fo->num/=so->num; break;
  320.    case AND    : fo->num=(fo->num && so->num) ? -1 : 0; break;
  321.    case OR    : fo->num=(fo->num || so->num) ? -1 : 0; break;
  322.    case GT     : 
  323.    case LT     : 
  324.    case GTE     : 
  325.    case LTE     : 
  326.    case NE    :
  327.    case NE2    :
  328.    case EQUAL    : execomp(fo,so,oppt[c].num); break;
  329.   }
  330.  }
  331.  
  332.  return(fo); 
  333.  
  334.  errend:    /* Find the end of the equation in case of error */
  335.   while(!end)
  336.   {
  337.    c=(**s); (*s)++;
  338.    switch(c)
  339.    {
  340.     case EXSTART : end++; break;
  341.     case EXINT : (*s)+=sizeof(float); break;
  342.     case EXSTR :
  343.     case EXVAR : while(**s) (*s)++; (*s)++; break;
  344.     case EXEND : end=1; if (!thisst) (*s)--; break;
  345.    }
  346.   }
  347.   
  348.  return(fo);
  349. }
  350.  
  351.  
  352. /***************************************************************************/
  353.  
  354. // Handle plus and minus
  355.  
  356. void expval::plumin(struct op *fo, struct op *so,int in)
  357. {
  358.  int n=(in==PLUS);
  359.  char *wsp;
  360.  
  361.  if (fo->optype==OPINT && so->optype==OPINT)    // number & number
  362.  {
  363.   fo->num-=so->num-2*n*so->num; return;
  364.  }
  365.  
  366.  if (fo->optype==OPSTR && so->optype==OPSTR)    // string & string
  367.  {
  368.   strcpy(exworkp,fo->str);
  369.   if (n) strcat(exworkp,so->str);
  370.   else
  371.   {
  372.    int x;
  373.    wsp=exworkp; while(*wsp++);
  374.    wsp--; wsp--; x=0; while(*wsp==' ') {wsp--; x++;}
  375.    wsp++; *wsp=0;
  376.    strcat(exworkp,so->str);
  377.    wsp=exworkp; while(*wsp++); wsp--; while(x--) *wsp++=' ';
  378.    *wsp=0;
  379.   }
  380.   fo->str=exealloc(strlen(exworkp)+1);
  381.   fo->oplen+=so->oplen;
  382.   return;
  383.  }
  384.  
  385.  if (n && fo->optype==OPINT && so->optype==OPDATE)
  386.  {
  387.   op temp=*so; *so=*fo; *fo=temp;
  388.  }
  389.  
  390.  if (fo->optype==OPDATE && so->optype==OPINT)
  391.  {
  392.   daystodate(fo->date,days(fo->date)-so->num+2*n*so->num); return;
  393.  }
  394.  
  395.  if (!n)
  396.  {
  397.   if (fo->optype==OPDATE && so->optype==OPDATE)
  398.   {
  399.    fo->optype=OPINT; 
  400.    fo->num=days(fo->date)-days(so->date);
  401.    return;
  402.   }
  403.  }
  404.  
  405.  err("Wrong operand Type");
  406. }
  407.  
  408.  
  409.